/**
 * SeaJS v2.0.0 | seajs.org/LICENSE.md
 */
(function(global, undefined) {

// Avoid conflicting when `sea.js` is loaded multiple times
    var _seajs = global.seajs;
    if (_seajs && _seajs.version) {
        return
    }

    var seajs = global.seajs = {
        // The current version of SeaJS being used
        version: "2.0.0"
    };


    /**
     * util-lang.js - The minimal language enhancement
     */

    function isType(type) {
        return function(obj) {
            return Object.prototype.toString.call(obj) === "[object " + type + "]";
        };
    }

    var isObject = isType("Object");
    var isString = isType("String");
    var isArray = Array.isArray || isType("Array");
    var isFunction = isType("Function");


    /**
     * util-log.js - The tiny log function
     */

// The safe wrapper for `console.xxx` functions
// log("message") ==> console.log("message")
// log("message", "warn") ==> console.warn("message")
    var log = seajs.log = function(msg, type) {

        global.console &&
            // Do NOT print `log(msg)` in non-debug mode
        (type || configData.debug) &&
            // Set the default value of type
        (console[type || (type = "log")]) &&
            // Call native method of console
        console[type](msg)
    }


    /**
     * util-events.js - The minimal events support
     */

    var eventsCache = seajs.events = {}

// Bind event
    seajs.on = function(event, callback) {
        if (!callback) return seajs;

        var list = eventsCache[event] || (eventsCache[event] = []);
        list.push(callback);

        return seajs;
    }

// Remove event. If `callback` is undefined, remove all callbacks for the
// event. If `event` and `callback` are both undefined, remove all callbacks
// for all events
    seajs.off = function(event, callback) {
        // Remove *all* events
        if (!(event || callback)) {
            seajs.events = eventsCache = {};
            return seajs;
        }

        var list = eventsCache[event]
        if (list) {
            if (callback) {
                for (var i = list.length - 1; i >= 0; i--) {
                    if (list[i] === callback) {
                        list.splice(i, 1);
                    }
                }
            }
            else {
                delete eventsCache[event];
            }
        }

        return seajs;
    }

// Emit event, firing all bound callbacks. Callbacks are passed the same
// arguments as `emit` is, apart from the event name
    var emit = seajs.emit = function(event, data) {
        var list = eventsCache[event], fn

        if (list) {
            // Copy callback lists to prevent modification
            list = list.slice()

            // Execute event callbacks
            while ((fn = list.shift())) {
                fn(data)
            }
        }

        return seajs
    }


    /**
     * util-path.js - The utilities for operating path such as id, uri
     */

    var DIRNAME_RE = /[^?#]*\//

    var DOT_RE = /\/\.\//g
    var MULTIPLE_SLASH_RE = /([^:\/])\/\/+/g
    var DOUBLE_DOT_RE = /\/[^/]+\/\.\.\//g

    var URI_END_RE = /\?|\.(?:css|js)$|\/$/
    var HASH_END_RE = /#$/

// Extract the directory portion of a path
// dirname("a/b/c.js?t=123#xx/zz") ==> "a/b/"
// ref: http://jsperf.com/regex-vs-split/2
    function dirname(path) {
        return path.match(DIRNAME_RE)[0]
    }

// Canonicalize a path
// realpath("http://test.com/a//./b/../c") ==> "http://test.com/a/c"
    function realpath(path) {
        // /a/b/./c/./d ==> /a/b/c/d
        path = path.replace(DOT_RE, "/")

        // "file:///a//b/c"  ==> "file:///a/b/c"
        // "http://a//b/c"   ==> "http://a/b/c"
        // "https://a//b/c"  ==> "https://a/b/c"
        // "/a/b//"          ==> "/a/b/"
        path = path.replace(MULTIPLE_SLASH_RE, "$1\/")

        // a/b/c/../../d  ==>  a/b/../d  ==>  a/d
        while (path.match(DOUBLE_DOT_RE)) {
            path = path.replace(DOUBLE_DOT_RE, "/")
        }

        return path
    }

// Normalize an uri
// normalize("path/to/a") ==> "path/to/a.js"
    function normalize(uri) {
        // Call realpath() before adding extension, so that most of uris will
        // contains no `.` and will just return in realpath() call
        uri = realpath(uri)

        // Add the default `.js` extension except that the uri ends with `#`
        if (HASH_END_RE.test(uri)) {
            uri = uri.slice(0, -1)
        }
        else if (!URI_END_RE.test(uri)) {
            uri += ".js"
        }

        // issue #256: fix `:80` bug in IE
        return uri.replace(":80/", "/")
    }


    var PATHS_RE = /^([^/:]+)(\/.+)$/
    var VARS_RE = /{([^{]+)}/g

    function parseAlias(id) {
        var alias = configData.alias
        return alias && isString(alias[id]) ? alias[id] : id
    }

    function parsePaths(id) {
        var paths = configData.paths
        var m

        if (paths && (m = id.match(PATHS_RE)) && isString(paths[m[1]])) {
            id = paths[m[1]] + m[2]
        }

        return id
    }

    function parseVars(id) {
        var vars = configData.vars

        if (vars && id.indexOf("{") > -1) {
            id = id.replace(VARS_RE, function(m, key) {
                return isString(vars[key]) ? vars[key] : m
            })
        }

        return id
    }

    function parseMap(uri) {
        var map = configData.map
        var ret = uri

        if (map) {
            for (var i = 0; i < map.length; i++) {
                var rule = map[i]

                ret = isFunction(rule) ?
                    (rule(uri) || uri) :
                    uri.replace(rule[0], rule[1])

                // Only apply the first matched rule
                if (ret !== uri) break
            }
        }

        return ret
    }


    var ABSOLUTE_RE = /:\//
    var RELATIVE_RE = /^\./
    var ROOT_RE = /^\//

    function isAbsolute(id) {
        return ABSOLUTE_RE.test(id)
    }

    function isRelative(id) {
        return RELATIVE_RE.test(id)
    }

    function isRoot(id) {
        return ROOT_RE.test(id)
    }


    var ROOT_DIR_RE = /^.*?\/\/.*?\//

    function addBase(id, refUri) {
        var ret

        if (isAbsolute(id)) {
            ret = id
        }
        else if (isRelative(id)) {
            ret = dirname(refUri || cwd) + id
        }
        else if (isRoot(id)) {
            ret = (cwd.match(ROOT_DIR_RE) || ["/"])[0] + id.substring(1)
        }
        // top-level id
        else {
            ret = configData.base + id
        }

        return ret
    }

    function id2Uri(id, refUri) {
        if (!id) return ""

        id = parseAlias(id)
        id = parsePaths(id)
        id = parseVars(id)
        id = addBase(id, refUri)
        id = normalize(id)
        id = parseMap(id)

        return id
    }


    var doc = document
    var loc = location
    var cwd = dirname(loc.href)
    var scripts = doc.getElementsByTagName("script")

// Recommend to add `seajs-node` id for the `sea.js` script element
    var loaderScript = doc.getElementById("seajsnode") ||
        scripts[scripts.length - 1]

// When `sea.js` is inline, set loaderDir to current working directory
    var loaderDir = dirname(getScriptAbsoluteSrc(loaderScript)) || cwd

    function getScriptAbsoluteSrc(node) {
        return node.hasAttribute ? // non-IE6/7
            node.src :
            // see http://msdn.microsoft.com/en-us/library/ms536429(VS.85).aspx
            node.getAttribute("src", 4)
    }

// Get/set current working directory
    seajs.cwd = function(val) {
        return val ? (cwd = realpath(val + "/")) : cwd
    }


    /**
     * util-request.js - The utilities for requesting script and style files
     * ref: tests/research/load-js-css/test.html
     */

    var head = doc.getElementsByTagName("head")[0] || doc.documentElement
    var baseElement = head.getElementsByTagName("base")[0]

    var IS_CSS_RE = /\.css(?:\?|$)/i
    var READY_STATE_RE = /^(?:loaded|complete|undefined)$/

    var currentlyAddingScript
    var interactiveScript

// `onload` event is supported in WebKit < 535.23 and Firefox < 9.0
// ref:
//  - https://bugs.webkit.org/show_activity.cgi?id=38995
//  - https://bugzilla.mozilla.org/show_bug.cgi?id=185236
//  - https://developer.mozilla.org/en/HTML/Element/link#Stylesheet_load_events
    var isOldWebKit = (navigator.userAgent
        .replace(/.*AppleWebKit\/(\d+)\..*/, "$1")) * 1 < 536


    function request(url, callback, charset) {
        var isCSS = IS_CSS_RE.test(url)
        var node = doc.createElement(isCSS ? "link" : "script")

        if (charset) {
            var cs = isFunction(charset) ? charset(url) : charset
            if (cs) {
                node.charset = cs
            }
        }

        addOnload(node, callback, isCSS)

        if (isCSS) {
            node.rel = "stylesheet"
            node.href = url
        }
        else {
            node.async = true
            node.src = url
        }

        // For some cache cases in IE 6-8, the script executes IMMEDIATELY after
        // the end of the insert execution, so use `currentlyAddingScript` to
        // hold current node, for deriving url in `define` call
        currentlyAddingScript = node

        // ref: #185 & http://dev.jquery.com/ticket/2709
        baseElement ?
            head.insertBefore(node, baseElement) :
            head.appendChild(node)

        currentlyAddingScript = undefined
    }

    function addOnload(node, callback, isCSS) {
        var missingOnload = isCSS && (isOldWebKit || !("onload" in node))

        // for Old WebKit and Old Firefox
        if (missingOnload) {
            setTimeout(function() {
                pollCss(node, callback)
            }, 1) // Begin after node insertion
            return
        }

        node.onload = node.onerror = node.onreadystatechange = function() {
            if (READY_STATE_RE.test(node.readyState)) {

                // Ensure only run once and handle memory leak in IE
                node.onload = node.onerror = node.onreadystatechange = null

                // Remove the script to reduce memory leak
                if (!isCSS && !configData.debug) {
                    head.removeChild(node)
                }

                // Dereference the node
                node = undefined

                callback()
            }
        }
    }

    function pollCss(node, callback) {
        var sheet = node.sheet
        var isLoaded

        // for WebKit < 536
        if (isOldWebKit) {
            if (sheet) {
                isLoaded = true
            }
        }
        // for Firefox < 9.0
        else if (sheet) {
            try {
                if (sheet.cssRules) {
                    isLoaded = true
                }
            } catch (ex) {
                // The value of `ex.name` is changed from "NS_ERROR_DOM_SECURITY_ERR"
                // to "SecurityError" since Firefox 13.0. But Firefox is less than 9.0
                // in here, So it is ok to just rely on "NS_ERROR_DOM_SECURITY_ERR"
                if (ex.name === "NS_ERROR_DOM_SECURITY_ERR") {
                    isLoaded = true
                }
            }
        }

        setTimeout(function() {
            if (isLoaded) {
                // Place callback here to give time for style rendering
                callback()
            }
            else {
                pollCss(node, callback)
            }
        }, 20)
    }

    function getCurrentScript() {
        if (currentlyAddingScript) {
            return currentlyAddingScript
        }

        // For IE6-9 browsers, the script onload event may not fire right
        // after the the script is evaluated. Kris Zyp found that it
        // could query the script nodes and the one that is in "interactive"
        // mode indicates the current script
        // ref: http://goo.gl/JHfFW
        if (interactiveScript && interactiveScript.readyState === "interactive") {
            return interactiveScript
        }

        var scripts = head.getElementsByTagName("script")

        for (var i = scripts.length - 1; i >= 0; i--) {
            var script = scripts[i]
            if (script.readyState === "interactive") {
                interactiveScript = script
                return interactiveScript
            }
        }
    }


    /**
     * util-deps.js - The parser for dependencies
     * ref: tests/research/parse-dependencies/test.html
     */

    var REQUIRE_RE = /"(?:\\"|[^"])*"|'(?:\\'|[^'])*'|\/\*[\S\s]*?\*\/|\/(?:\\\/|[^/\r\n])+\/(?=[^\/])|\/\/.*|\.\s*require|(?:^|[^$])\brequire\s*\(\s*(["'])(.+?)\1\s*\)/g
    var SLASH_RE = /\\\\/g

    function parseDependencies(code) {
        var ret = []

        code.replace(SLASH_RE, "")
            .replace(REQUIRE_RE, function(m, m1, m2) {
                if (m2) {
                    ret.push(m2)
                }
            })

        return ret
    }


    /**
     * module.js - The core of module loader
     */

    var cachedModules = seajs.cache = {}
    var anonymousModuleData

    var fetchingList = {}
    var fetchedList = {}
    var callbackList = {}
    var waitingsList = {}

// 1 - The module file is being fetched now
// 2 - The module data has been saved to cachedModules
// 3 - The module and all its dependencies are ready to execute
// 4 - The module is being executed
// 5 - The module is executed and `module.exports` is available
    var STATUS_FETCHING = 1
    var STATUS_SAVED = 2
    var STATUS_LOADED = 3
    var STATUS_EXECUTING = 4
    var STATUS_EXECUTED = 5


    function Module(uri) {
        this.uri = uri
        this.dependencies = []
        this.exports = null
        this.status = 0
    }

    function resolve(ids, refUri) {
        if (isArray(ids)) {
            var ret = []
            for (var i = 0; i < ids.length; i++) {
                ret[i] = resolve(ids[i], refUri)
            }
            return ret
        }

        // Emit `resolve` event for plugins such as plugin-text
        var data = { id: ids, refUri: refUri }
        emit("resolve", data)

        return data.uri || id2Uri(data.id, refUri)
    }

    function use(uris, callback) {
        isArray(uris) || (uris = [uris])

        load(uris, function() {
            var exports = []

            for (var i = 0; i < uris.length; i++) {
                exports[i] = getExports(cachedModules[uris[i]])
            }

            if (callback) {
                callback.apply(global, exports)
            }
        })
    }

    function load(uris, callback) {
        var unloadedUris = getUnloadedUris(uris)

        if (unloadedUris.length === 0) {
            callback()
            return
        }

        // Emit `load` event for plugins such as plugin-combo
        emit("load", unloadedUris)

        var len = unloadedUris.length
        var remain = len

        for (var i = 0; i < len; i++) {
            (function(uri) {
                var mod = cachedModules[uri]

                if (mod.dependencies.length) {
                    loadWaitings(function(circular) {
                        mod.status < STATUS_SAVED ? fetch(uri, cb) : cb()
                        function cb() {
                            done(circular)
                        }
                    })
                }
                else {
                    mod.status < STATUS_SAVED ?
                        fetch(uri, loadWaitings) : done()
                }

                function loadWaitings(cb) {
                    cb || (cb = done)

                    var waitings = getUnloadedUris(mod.dependencies)
                    if (waitings.length === 0) {
                        cb()
                    }
                    // Break circular waiting callbacks
                    else if (isCircularWaiting(mod)) {
                        printCircularLog(circularStack)
                        circularStack.length = 0
                        cb(true)
                    }
                    // Load all unloaded dependencies
                    else {
                        waitingsList[uri] = waitings
                        load(waitings, cb)
                    }
                }

                function done(circular) {
                    if (!circular && mod.status < STATUS_LOADED) {
                        mod.status = STATUS_LOADED
                    }

                    if (--remain === 0) {
                        callback()
                    }
                }

            })(unloadedUris[i])
        }
    }

    function fetch(uri, callback) {
        cachedModules[uri].status = STATUS_FETCHING

        // Emit `fetch` event for plugins such as plugin-combo
        var data = { uri: uri }
        emit("fetch", data)
        var requestUri = data.requestUri || uri

        if (fetchedList[requestUri]) {
            callback()
            return
        }

        if (fetchingList[requestUri]) {
            callbackList[requestUri].push(callback)
            return
        }

        fetchingList[requestUri] = true
        callbackList[requestUri] = [callback]

        // Emit `request` event for plugins such as plugin-text
        var charset = configData.charset
        emit("request", data = {
            uri: uri,
            requestUri: requestUri,
            callback: onRequested,
            charset: charset
        })

        if (!data.requested) {
            request(data.requestUri, onRequested, charset)
        }

        function onRequested() {
            delete fetchingList[requestUri]
            fetchedList[requestUri] = true

            // Save meta data of anonymous module
            if (anonymousModuleData) {
                save(uri, anonymousModuleData)
                anonymousModuleData = undefined
            }

            // Call callbacks
            var fn, fns = callbackList[requestUri]
            delete callbackList[requestUri]
            while ((fn = fns.shift())) fn()
        }
    }

    function define(id, deps, factory) {
        // define(factory)
        if (arguments.length === 1) {
            factory = id
            id = undefined
        }

        // Parse dependencies according to the module factory code
        if (!isArray(deps) && isFunction(factory)) {
            deps = parseDependencies(factory.toString())
        }

        var data = { id: id, uri: resolve(id), deps: deps, factory: factory }

        // Try to derive uri in IE6-9 for anonymous modules
        if (!data.uri && doc.attachEvent) {
            var script = getCurrentScript()

            if (script) {
                data.uri = script.src
            }
            else {
                log("Failed to derive: " + factory)

                // NOTE: If the id-deriving methods above is failed, then falls back
                // to use onload event to get the uri
            }
        }

        // Emit `define` event, used in plugin-nocache, seajs node version etc
        emit("define", data)

        data.uri ? save(data.uri, data) :
            // Save information for "saving" work in the script onload event
            anonymousModuleData = data
    }

    function save(uri, meta) {
        var mod = getModule(uri)

        // Do NOT override already saved modules
        if (mod.status < STATUS_SAVED) {
            // Let the id of anonymous module equal to its uri
            mod.id = meta.id || uri

            mod.dependencies = resolve(meta.deps || [], uri)
            mod.factory = meta.factory

            if (mod.factory !== undefined) {
                mod.status = STATUS_SAVED
            }
        }
    }

    function exec(mod) {
        // Return `null` when `mod` is invalid
        if (!mod) {
            return null
        }

        // When module is executed, DO NOT execute it again. When module
        // is being executed, just return `module.exports` too, for avoiding
        // circularly calling
        if (mod.status >= STATUS_EXECUTING) {
            return mod.exports
        }

        mod.status = STATUS_EXECUTING


        function resolveInThisContext(id) {
            return resolve(id, mod.uri)
        }

        function require(id) {
            return getExports(cachedModules[resolveInThisContext(id)])
        }

        require.resolve = resolveInThisContext

        require.async = function(ids, callback) {
            use(resolveInThisContext(ids), callback)
            return require
        }


        var factory = mod.factory

        var exports = isFunction(factory) ?
            factory(require, mod.exports = {}, mod) :
            factory

        mod.exports = exports === undefined ? mod.exports : exports
        mod.status = STATUS_EXECUTED

        return mod.exports
    }

    Module.prototype.destroy = function() {
        delete cachedModules[this.uri]
        delete fetchedList[this.uri]
    }


// Helpers

    function getModule(uri) {
        return cachedModules[uri] ||
            (cachedModules[uri] = new Module(uri))
    }

    function getUnloadedUris(uris) {
        var ret = []

        for (var i = 0; i < uris.length; i++) {
            var uri = uris[i]
            if (uri && getModule(uri).status < STATUS_LOADED) {
                ret.push(uri)
            }
        }

        return ret
    }

    function getExports(mod) {
        var exports = exec(mod)
        if (exports === null && (!mod || !IS_CSS_RE.test(mod.uri))) {
            emit("error", mod)
        }
        return exports
    }

    var circularStack = []

    function isCircularWaiting(mod) {
        var waitings = waitingsList[mod.uri] || []
        if (waitings.length === 0) {
            return false
        }

        circularStack.push(mod.uri)
        if (isOverlap(waitings, circularStack)) {
            cutWaitings(waitings)
            return true
        }

        for (var i = 0; i < waitings.length; i++) {
            if (isCircularWaiting(cachedModules[waitings[i]])) {
                return true
            }
        }

        circularStack.pop()
        return false
    }

    function isOverlap(arrA, arrB) {
        for (var i = 0; i < arrA.length; i++) {
            for (var j = 0; j < arrB.length; j++) {
                if (arrB[j] === arrA[i]) {
                    return true
                }
            }
        }
        return false
    }

    function cutWaitings(waitings) {
        var uri = circularStack[0]

        for (var i = waitings.length - 1; i >= 0; i--) {
            if (waitings[i] === uri) {
                waitings.splice(i, 1)
                break
            }
        }
    }

    function printCircularLog(stack) {
        stack.push(stack[0])
        log("Circular dependencies: " + stack.join(" -> "))
    }

    function preload(callback) {
        var preloadMods = configData.preload
        var len = preloadMods.length

        if (len) {
            use(resolve(preloadMods), function() {
                // Remove the loaded preload modules
                preloadMods.splice(0, len)

                // Allow preload modules to add new preload modules
                preload(callback)
            })
        }
        else {
            callback()
        }
    }


// Public API

    seajs.use = function(ids, callback) {
        // Load preload modules before all other modules
        preload(function() {
            use(resolve(ids), callback)
        })
        return seajs
    }

    Module.load = use
    seajs.resolve = id2Uri
    global.define = define

    seajs.require = function(id) {
        return (cachedModules[id2Uri(id)] || {}).exports
    }


    /**
     * config.js - The configuration for the loader
     */

    var configData = config.data = {
        // The root path to use for id2uri parsing
        base: (function() {
            var ret = loaderDir

            // If loaderUri is `http://test.com/libs/seajs/[seajs/1.2.3/]sea.js`, the
            // baseUri should be `http://test.com/libs/`
            var m = ret.match(/^(.+?\/)(?:seajs\/)+(?:\d[^/]+\/)?$/)
            if (m) {
                ret = m[1]
            }

            return ret
        })(),

        // The charset for requesting files
        charset: "utf-8",

        // Modules that are needed to load before all other modules
        preload: []

        // debug - Debug mode. The default value is false
        // alias - An object containing shorthands of module id
        // paths - An object containing path shorthands in module id
        // vars - The {xxx} variables in module id
        // map - An array containing rules to map module uri
        // plugins - An array containing needed plugins
    }

    function config(data) {
        for (var key in data) {
            var curr = data[key];

            // Convert plugins to preload config
            if (curr && key === "plugins") {
                key = "preload"
                curr = plugin2preload(curr);
            }

            var prev = configData[key]

            // Merge object config such as alias, vars
            if (prev && isObject(prev)) {
                for (var k in curr) {
                    prev[k] = curr[k];
                }
            }
            else {
                // Concat array config such as map, preload
                if (isArray(prev)) {
                    curr = prev.concat(curr);
                }
                // Make sure that `configData.base` is an absolute directory
                else if (key === "base") {
                    curr = normalize(addBase(curr + "/"))
                }

                // Set config
                configData[key] = curr;
            }
        }

        emit("config", data)
        return seajs;
    }

    seajs.config = config

    function plugin2preload(arr) {
        var ret = [], name;

        while ((name = arr.shift())) {
            ret.push(loaderDir + "plugin-" + name);
        }
        return ret;
    }


    /**
     * bootstrap.js - Initialize the plugins and load the entry module
     */

    config({
        // Get initial plugins
        plugins: (function() {
            var ret;

            // Convert `seajs-xxx` to `seajs-xxx=1`
            // NOTE: use `seajs-xxx=1` flag in url or cookie to enable `plugin-xxx`
            var str = loc.search.replace(/(seajs-\w+)(&|$)/g, "$1=1$2");

            // Add cookie string
            str += " " + doc.cookie;

            // Exclude seajs-xxx=0
            str.replace(/seajs-(\w+)=1/g, function(m, name) {
                (ret || (ret = [])).push(name);
            });

            return ret;
        })()
    })

    var dataConfig = loaderScript.getAttribute("data-config")
    var dataMain = loaderScript.getAttribute("data-main")

// Add data-config to preload modules
    if (dataConfig) {
        configData.preload.push(dataConfig)
    }

//    if (dataMain) {
//        seajs.use(dataMain)
//    }

// Enable to load `sea.js` self asynchronously
    if (_seajs && _seajs.args) {
        var methods = ["define", "config", "use"]
        var args = _seajs.args
        for (var g = 0; g < args.length; g += 2) {
            seajs[methods[args[g]]].apply(seajs, args[g + 1])
        }
    }

    /*
     ;(function(m, o, d, u, l, a, r) {
     if(m[o]) return
     function f(n) { return function() { r.push(n, arguments); return a } }
     m[o] = a = { args: (r = []), config: f(1), use: f(2) }
     m.define = f(0)
     u = d.createElement("script")
     u.id = o + "node"
     u.async = true
     u.src = "path/to/sea.js"
     l = d.getElementsByTagName("head")[0]
     l.appendChild(u)
     })(window, "seajs", document);
     */

})(this);

/**
 * The plugin to load text resources such as template, json
 */
(function(seajs, global) {

    var plugins = {}
    var uriCache = {}

    function addPlugin(o) {
        plugins[o.name] = o
    }

    // normal text
    addPlugin({
        name: "text",

        ext: [".tpl", ".html"],

        exec: function(uri, content) {
            globalEval('define("' + uri + '#", [], "' + jsEscape(content) + '")')
        }
    })

    // json
    addPlugin({
        name: "json",

        ext: [".json"],

        exec: function(uri, content) {
            globalEval('define("' + uri + '#", [], ' + content + ')')
        }
    })

    seajs.on("resolve", function(data) {
        var id = data.id
        if (!id) return ""

        var pluginName
        var m

        // text!path/to/some.xx
        if ((m = id.match(/^(\w+)!(.+)$/)) && isPlugin(m[1])) {
            pluginName = m[1]
            id = m[2]
        }

        var uri = seajs.resolve(id, data.refUri)
        var t = uri.replace(/\.(?:js|css)(\?|$)/, "$1")

        // http://path/to/a.tpl
        // http://path/to/c.json?v2
        if (!pluginName && (m = t.match(/[^?]+(\.\w+)(?:\?|$)/))) {
            pluginName = getPluginName(m[1])
        }

        if (pluginName) {
            uri = uri.replace(/\.js(?=$|\?)/, "")
            uriCache[uri] = pluginName
        }

        data.uri = uri
    })

    seajs.on("request", function(data) {
        var name = uriCache[data.uri]

        if (name) {
            xhr(data.requestUri, function(content) {
                plugins[name].exec(data.uri, content)
                data.callback()
            })

            data.requested = true
        }
    })


    // Helpers

    function isPlugin(name) {
        return name && plugins.hasOwnProperty(name)
    }

    function getPluginName(ext) {
        for (var k in plugins) {
            if (isPlugin(k)) {
                var exts = "," + plugins[k].ext.join(",") + ","
                if (exts.indexOf("," + ext + ",") > -1) {
                    return k
                }
            }
        }
    }

    function xhr(url, callback) {
        var r = global.ActiveXObject ?
            new global.ActiveXObject("Microsoft.XMLHTTP") :
            new global.XMLHttpRequest()

        r.open("GET", url, true)

        r.onreadystatechange = function() {
            if (r.readyState === 4) {
                // Support local file
                if (r.status > 399 && r.status < 600) {
                    throw new Error("Could not load: " + url + ", status = " + r.status)
                }
                else {
                    callback(r.responseText)
                }
            }
        }

        return r.send(null)
    }

    function globalEval(content) {
        if (content && /\S/.test(content)) {
            (global.execScript || function(content) {
                (global.eval || eval).call(global, content)
            })(content)
        }
    }

    function jsEscape(content) {
        return content.replace(/(["\\])/g, "\\$1")
            .replace(/[\f]/g, "\\f")
            .replace(/[\b]/g, "\\b")
            .replace(/[\n]/g, "\\n")
            .replace(/[\t]/g, "\\t")
            .replace(/[\r]/g, "\\r")
            .replace(/[\u2028]/g, "\\u2028")
            .replace(/[\u2029]/g, "\\u2029")
    }

    // For node environment
    if (typeof module !== "undefined") {
        xhr = function(filename, callback) {
            callback(require("fs").readFileSync(pure(filename), "utf8"))
        }
    }

    function pure(uri) {
        // Remove timestamp etc
        return uri.replace(/\?.*$/, "")
    }

})(seajs, this);

/**
 * seajs配置，页面入口模块和样式加载
 * @author liuqing
 */
(function(global, undefined) {
seajs.config({
    "alias": {
        "jquery": "lib/jquery/jquery1.11.1",
        "bootstrap": "lib/bootstrap/js/bootstrap.min.js",
        "json": "lib/common/json2",
        "com": "lib/common/common",
        "util": "lib/common/CommonUtil"
    }
});

seajs.use("jquery", function($) {
    var seajsNode = $("#seajsnode"),
        loaderScript = seajsNode.length ? seajsNode : $("script").last(),
        main = loaderScript.attr("data-main"),  //获取入口模块配置
        css = loaderScript.attr("data-css");

    if(css) {
        if(css.lastIndexOf(".css") < 0) {
            throw "data-css配置的文件类型不正确，请仔细检查！";
        }
        seajs.use(css);
    }
    global['$'] = $;
    
    seajs.use(["com", "util", "json"], function(c, u, j){});

    if(main) {
        $(function() {
            seajs.use(main, function() {
                $("body").show();
            });
        });
    }
});
})(this);